package com.rz.paas.baselib.netRequest.request.okhttp

import android.util.Log
import com.rz.paas.baselib.netRequest.convert.Convert
import com.rz.paas.baselib.netRequest.convert.JsonConvert
import com.rz.paas.baselib.netRequest.response.ApiResponse
import com.rz.paas.baselib.netRequest.response.JsonCallback
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import java.io.IOException
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.*
import java.util.concurrent.TimeUnit

abstract class Request<T, R : Request<T, R>> constructor(@JvmField val url: String) {

    @JvmField
    var params = HashMap<String, Any>()
    var headers = HashMap<String, String>()
    private var mType: Type? = null
    val baseUrl = "ssss"
    fun addParam(key: String, value: Any): R? {
        try {
            if (value.javaClass == String::class.java) {
                params.put(key, value)
            } else {
                val field = value.javaClass.getField("TYPE")
                val claz = field[null] as Class<*>
                if (claz.isPrimitive) {
                    params.put(key, value)
                }
            }
        } catch (e: NoSuchFieldException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        }
        return this as R
    }


    fun addHeader(key: String, value: String): R {
        headers[key] = value
        return this as R
    }

    private fun getCall(): Call? {
        val builder = okhttp3.Request.Builder()
        addHeaders(builder)
        val request = generateRequest(builder)
        return httpClient.newCall(request)
    }

    abstract fun generateRequest(builder: okhttp3.Request.Builder): okhttp3.Request

    private fun addHeaders(builder: okhttp3.Request.Builder) {
        for ((key, value) in headers) {
            builder.addHeader(key, value)
        }
    }

    val DEBUG = false
    private val loggingInterceptor by lazy {
        val logInterceptor = HttpLoggingInterceptor()
        if (DEBUG) {
            logInterceptor.level = HttpLoggingInterceptor.Level.BODY
        } else {
            logInterceptor.level = HttpLoggingInterceptor.Level.NONE
        }

        logInterceptor
    }
    private val httpClient by lazy {

        OkHttpClient.Builder()
            .connectTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
            .addInterceptor(loggingInterceptor)
            .addInterceptor {
                val request = it.request()
                    .newBuilder()
//                    .addHeader("X-Access-Id", AppConstant.LUXX_ACCESS_ID)
//                    .addHeader("X-Access-Secret", AppConstant.LUXX_ACCESS_SECRET)
                    .build()
                it.proceed(request)
            }
            .build()
    }

    open fun execute(): ApiResponse<T?>? {

        var result: ApiResponse<T?>? = null
        try {
            val response = getCall()!!.execute()
            result = parseResponse(response, null)
        } catch (e: IOException) {
            e.printStackTrace()
            if (result == null) {
                result = ApiResponse()
                result.msg = e.message
            }
        }
        return result
    }

    open fun execute(callback: JsonCallback<T>) {

        getCall()!!.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                val result: ApiResponse<T> = ApiResponse()
                result.msg = e.message
                callback.onError(result)
            }

            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                val result = parseResponse(response, callback)
//                if (!result.success) {
//                    callback.onError(result)
//                } else {
                    callback.onSuccess(result)
//                }
            }
        })
    }

    private fun parseResponse(response: Response, callback: JsonCallback<T>?): ApiResponse<T?>? {
        var msg: String? = null
        var status = response.code()
        var success = response.isSuccessful
        val result: ApiResponse<T?> = ApiResponse()
        val convert: Convert<*> = JsonConvert()
        try {
            val content = response.body()!!.string()
            if (success) {
                if (callback != null) {
                    val argument =
                        (callback.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]
                    result.body = convert.convert(content, argument) as T
                } else if (mType != null) {
                    result.body = convert.convert(content, mType) as T
                } else {
                    Log.e("request", "parseResponse: 无法解析 ")
                }
            } else {
                msg = content
            }
        } catch (e: Exception) {
            msg = e.message
            success = false
            status = 0
        }

//        result.success = success
//        result.status = status
        result.msg = msg


        return result
    }


    open fun responseType(type: Type): R {
        mType = type
        return this as R
    }
}